package cn.xiaolang.function.network.io;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * 多路复用IO示例
 *
 * @author Dean
 * @date 2022-02-13
 */
public class SocketServerMultiplexingIO {

    public static void main(String[] args) {
        try {
            ServerSocketChannel ssc = ServerSocketChannel.open();
            ssc.socket().bind(new InetSocketAddress(10010));
            System.out.println("server up use port:" + 10010);
            // NON BLOCKING
            ssc.configureBlocking(false);

            // 创建并向selector注册一个OP_ACCEPT事件，然后返回该通道的key
            Selector selector = Selector.open();
            ssc.register(selector, SelectionKey.OP_ACCEPT);
            while (true) {
                // 如果没有事件就绪即结果为0，则select()阻塞不往下执行
                selector.select();
                // 取得所有已就绪可处理的事件key集合
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> it = selectedKeys.iterator();
                while (it.hasNext()) {
                    // 根据事件的key进行调度
                    SelectionKey next = it.next();
                    // 处理后删除
                    it.remove();
                    if (next.isAcceptable()) {
                        // selector acceptable event
                        // 接收client的连接
                        SocketChannel sc = ssc.accept();
                        if (sc != null) {
                            System.out.println(sc.socket().getRemoteSocketAddress().toString() + " connected! ");
                            // NON BLOCKING
                            sc.configureBlocking(false);
                            // 向selector注册一个OP_READ事件，然后返回该通道的key
                            sc.register(selector, SelectionKey.OP_READ);
                        }
                    } else if (next.isReadable()) {
                        // selector readable event
                        SocketChannel sc = (SocketChannel) next.channel();
                        // non-blocking下不可用Readers，因为Readers不支持
                        byte[] arr = new byte[1024];
                        ByteBuffer buf = ByteBuffer.wrap(arr);
                        if (sc.read(buf) == -1) {
                            System.out.println(sc.socket().getRemoteSocketAddress().toString() + " closed! ");
                            sc.close();
                        } else {
                            System.out.println("received data from client: " + sc.socket().getRemoteSocketAddress().toString() + " ===> " + new String(arr));
                        }
                    } else if (next.isWritable()) {
                        System.out.println("selector writable event");
                    }

                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

